package com.telnetnz.ticketdesk.action.ticket;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.rockbb.common.simpleframe.action.MultipartFile;
import com.rockbb.common.simpleframe.config.SimpleConfig;
import com.rockbb.common.sso.session.SessionConstants;
import com.rockbb.common.utilities.security.StringDigest;
import com.rockbb.common.utilities.time.TimeUtil;
import com.telnetnz.ticketdesk.action.base.BasicSessionPageAccAction;
import com.telnetnz.ticketdesk.action.common.CommonUtils;
import com.telnetnz.ticketdesk.bean.Attachment;
import com.telnetnz.ticketdesk.bean.Project;
import com.telnetnz.ticketdesk.bean.ProjectToUser;
import com.telnetnz.ticketdesk.bean.Tag;
import com.telnetnz.ticketdesk.bean.Ticket;
import com.telnetnz.ticketdesk.bean.User;
import com.telnetnz.ticketdesk.service.AttachmentService;
import com.telnetnz.ticketdesk.service.OperationLogService;
import com.telnetnz.ticketdesk.service.ProjectService;
import com.telnetnz.ticketdesk.service.ProjectToUserService;
import com.telnetnz.ticketdesk.service.TagService;
import com.telnetnz.ticketdesk.service.TicketService;
import com.telnetnz.ticketdesk.service.TicketToTagService;
import com.telnetnz.ticketdesk.service.TicketToUserService;
import com.telnetnz.ticketdesk.service.UserService;

public class TicketEditAction extends BasicSessionPageAccAction
{
	private static Logger logger = Logger.getLogger(TicketEditAction.class);

	public String doAssign()
	{
		RequestBean bean = new DefaultRequestBean();
		long ticketId = bean.getLong("ticket_id", 0L);
		long ownerId = bean.getLong("owner_id", 0L);
		Ticket ticket = TicketService.getTicket(ticketId);
		User owner = UserService.getUser(ownerId);
		if (ticket != null && owner != null && (ticket.getOwner() == null || ticket.getOwnerId() == getSession().getSession_uuid()))
		{
			ticket.setOwnerId(ownerId);
			Map<String, List<String>> diff = ticket.compare();
			ticket.setUpdaterId(getSession().getSession_uuid());
			TicketService.update(ticket);

			OperationLogService.addLog(
					OperationLogService.OBJECT_TYPE_TICKET,
					ticket.getId(),
					getSession().getSession_uuid(),
					getContext().getActionName(),
					diff);
		}
		return redirect(bean.getRedirect());
	}

	public String doUpdate()
	{
		TicketUpdateBean bean = new TicketUpdateBean();
		if (bean.getTicket() != null)
		{
			if (bean.isSubmitted() && bean.validate())
			{
				Map<String, List<String>> diff = bean.getTicket().compare();
				bean.getTicket().setUpdaterId(getSession().getSession_uuid());
				TicketService.update(bean.getTicket());

				TicketService.sendUpdateNotification(bean.getTicket(), 0);

				OperationLogService.addLog(
						OperationLogService.OBJECT_TYPE_TICKET,
						bean.getTicket().getId(),
						getSession().getSession_uuid(),
						getContext().getActionName(),
						diff);
			}
		}

		return redirect(bean.getRedirect());
	}

	public class TicketUpdateBean extends RequestBean
	{
		private Ticket ticket;

		public Ticket getTicket() {
			return ticket;
		}

		@Override
		protected void loadRequest() 
		{
			long id = getLong("ticket_id", 0L);
			ticket = TicketService.getRawTicket(id);

			if (ticket != null)
			{
				if (isSubmitted())
				{
					ticket.setProjectId(getInt("project_id"));
					ticket.setType(getInt("type", 0, 0, TicketService.TYPES.length - 1));
					ticket.setPriority(getInt("priority", 0, 0, TicketService.PRIORITIES.length -1));
					ticket.setStatus(getInt("status", 0, 0, TicketService.STATUSES.length -1));
					ticket.setOwnerId(getLong("owner_id", 0L));
				}
			}
		}

		@Override
		protected boolean validate() 
		{
			boolean flag = true;
			if (ticket.getProjectId() == 0)
			{
				flag = false;
				put_error_msg("project_id", langRes.get("global.content-cannot-be-empty"));
			}
			else
			{
				Project dummy = ProjectService.getProject(ticket.getProjectId());
				if (dummy == null)
				{
					flag = false;
					put_error_msg("project_id", langRes.get("project.project-not-exist"));
				}
			}

			return flag;
		}
	}

	public String doEdit()
	{
		TicketEditBean bean = new TicketEditBean();
		if (bean.getTicket() == null)
			return this.message_box(
					langRes.get("global.operation-fail"),
					langRes.get("ticket.ticket-not-exist", new String[]{bean.getRedirect()}),
					bean.getRedirect(),
					2);
		else if (!isSuperSession() && !bean.getTicket().isEditable(getSession().getSession_uuid()))
			return this.message_box(
					langRes.get("global.no-permission"),
					langRes.get("global.no-permission-redirect", new String[]{bean.getRedirect()}),
					bean.getRedirect(),
					2);

		if (bean.isSubmitted())
		{
			if (bean.getAddAttachment().length() > 0 || bean.getDeleteAttachmentId() > 0L)
			{
				// Go back to INPUT
			}
			else
			{
				if (bean.validate())
				{
					String message;
					if(bean.getTicket().getId() == 0)
					{
						bean.getTicket().setCreatorId(getSession().getSession_uuid());
						bean.getTicket().setUpdaterId(getSession().getSession_uuid());
						TicketService.add(bean.getTicket());

						OperationLogService.addLog(
								OperationLogService.OBJECT_TYPE_TICKET,
								bean.getTicket().getId(),
								getSession().getSession_uuid(),
								getContext().getActionName(),
								OperationLogService.createSimpleDiff("name", new String[]{"null", bean.getTicket().getSubject()}));

						message = langRes.get("ticket.ticket-add-success-redirect", new String[]{bean.getRedirect()});
					}
					else
					{
						Map<String, List<String>> diff = bean.getTicket().compare();
						bean.getTicket().setUpdaterId(getSession().getSession_uuid());
						TicketService.update(bean.getTicket());

						OperationLogService.addLog(
								OperationLogService.OBJECT_TYPE_TICKET,
								bean.getTicket().getId(),
								getSession().getSession_uuid(),
								getContext().getActionName(),
								diff);

						message = langRes.get("ticket.ticket-update-success-redirect", new String[]{bean.getRedirect()});
					}

					TicketToTagService.deleteByTicketId(bean.getTicket().getId());
					for (Tag tag : bean.getTags())
					{
						TicketToTagService.add(bean.getTicket().getId(), tag.getId(), tag.getName());
					}
					TicketService.sendUpdateNotification(bean.getTicket(), 0);

					for (Attachment attachment: bean.getAttachments())
					{
						Attachment dummy = AttachmentService.getAttachment(attachment.getId());
						if (dummy.getTicketId() == 0L)
						{
							dummy.setTicketId(bean.getTicket().getId());
							AttachmentService.update(dummy);
						}
					}

					return this.message_box(
							langRes.get("global.operation-success"), 
							message,
							bean.getRedirect(),
							2
						);
				}
			}
		}

		this.put_page_key("bean", bean);
		this.put_page_key("owner_options", CommonUtils.buildUserDropdown(
				UserService.getByPageAndCondition(
						0, 
						100, 
						UserService.ORDER_BY_NAME, 
						1, 
						SessionConstants.USER_ID_ANONYMOUS, 
						null, 
						null), 
				bean.getTicket().getOwnerId(), 
				true));

		List<ProjectToUser> projectToUsers = ProjectToUserService.getByUserId(getSession().getSession_uuid());
		List<Integer> projectIds = new ArrayList<Integer>();
		for (ProjectToUser projectToUser : projectToUsers)
		{
			projectIds.add(projectToUser.getProjectId());
		}

		this.put_page_key("project_options", CommonUtils.buildProjectDropdown(
				ProjectService.getByPageAndCondition(0, 100, ProjectService.ORDERBY_NAME, 1, null), 
				bean.getTicket().getProjectId(), 
				false));
		this.put_page_key("type_options", CommonUtils.buildSingleDropdown(langRes, "ticket.type.", TicketService.TYPES, bean.getTicket().getType(), false));
		this.put_page_key("priority_options", CommonUtils.buildSingleDropdown(langRes, "ticket.priority.", TicketService.PRIORITIES, bean.getTicket().getPriority(), false));
		this.put_page_key("status_options", CommonUtils.buildSingleDropdown(langRes, "ticket.status.", TicketService.STATUSES, bean.getTicket().getStatus(), false));
		this.put_page_key("tag_options", CommonUtils.buildTagDropdown(TagService.getAllTags(), bean.getTags(), false));
		this.put_page_key("post_action", baseLink());
		this.put_js_key("source_files", new String[] {
				SimpleConfig.getConfig("static_file_url")+"/js/jquery-ui.min.js",
				SimpleConfig.getConfig("static_file_url")+"/js/jquery-ui-timepicker-addon.js",
				SimpleConfig.getConfig("static_file_url")+"/js/jquery.multiselect.min.js",
				SimpleConfig.getConfig("static_file_url")+"/js/tiny_mce/tiny_mce.js"});

		this.put_css_key("source_files", new String[] {
				SimpleConfig.getConfig("static_file_url")+"/js/jquery-ui.css",
				SimpleConfig.getConfig("static_file_url")+"/js/jquery.multiselect.css"});

		return INPUT;
	}

	public class TicketEditBean extends FileRequestBean
	{
		private Ticket ticket;
		private List<Tag> tags;
		private List<Attachment> attachments;
		private String addAttachment;
		private long deleteAttachmentId;

		public String getAddAttachment() {
			return addAttachment;
		}

		public long getDeleteAttachmentId() {
			return deleteAttachmentId;
		}

		public Ticket getTicket() {
			return ticket;
		}

		public List<Tag> getTags() {
			return tags;
		}

		public List<Attachment> getAttachments() {
			return attachments;
		}

		@Override
		protected void loadRequest() 
		{
			long id = getLong("id", 0L);
			if (id > 0)
			{
				ticket = TicketService.getRawTicket(id);
			}
			else
			{
				ticket = new Ticket();
				ticket.initialize();
				ticket.setProjectId(getInt("project_id"));
			}

			if (ticket != null)
			{
				if (isSubmitted())
				{
					ticket.setProjectId(getInt("project_id"));
					ticket.setType(getInt("type", 0, 0, TicketService.TYPES.length - 1));
					ticket.setPriority(getInt("priority", 0, 0, TicketService.PRIORITIES.length -1));
					ticket.setStatus(getInt("status", 0, 0, TicketService.STATUSES.length -1));
					ticket.setSubject(get("subject"));
					ticket.setOwnerId(getLong("owner_id", 0L));
					ticket.setContent(get("ticket_content"));
					if (get("start_date").length() > 0) 
						ticket.setStartDate(TimeUtil.getDate(get("start_date"),"yyyy-MM-dd"));
					if (get("due_date").length() > 0) 
						ticket.setDueDate(TimeUtil.getDate(get("due_date"),"yyyy-MM-dd"));

					// Tags
					int[] array = getIntArray("tags", new int[]{}, null);
					tags = new ArrayList<Tag>();
					if (array != null && array.length > 0)
					{
						for (int tagId: array)
						{
							Tag tag = TagService.getTag(tagId);
							if (tag != null)
							{
								tags.add(tag);
							}
						}
					}

					// Attachments
					long[] array2 = getLongArray("attachments", new long[]{}, null);
					attachments = new ArrayList<Attachment>();
					if (array2 != null && array2.length > 0)
					{
						for (long attId: array2)
						{
							Attachment att = AttachmentService.getAttachment(attId);
							if (att != null)
							{
								attachments.add(att);
							}
						}
					}

					// Delete attachment
					deleteAttachmentId = getLong("delete_attachment_id", 0L);
					if (deleteAttachmentId > 0L)
					{
						for (int i = 0; i < attachments.size(); i ++)
						{
							if (attachments.get(i).getId() == deleteAttachmentId)
							{
								AttachmentService.deleteByPrimaryKey(deleteAttachmentId);
								attachments.remove(i);
								break;
							}
						}
					}

					// New attachment
					addAttachment = get("add_attachment");

					// Add new attachment in spite of "att_attachment", because sometimes it is submitted by the Submit button
					MultipartFile multipartFile = getFile("fileupload");
					if(multipartFile != null && multipartFile.getSize() > 0 && attachmentValidate(multipartFile))
					{
						Attachment attachment = new Attachment();
						attachment.initialize();
						attachment.setTicketId(id);
						attachment.setCreatorId(getSession().getSession_uuid());
						attachment.setSize(multipartFile.getSize());
						attachment.setName(multipartFile.getOriginalFilename());

						// Guess the mime-type
						String mimeType = multipartFile.getContentType();
						if (mimeType.equals("application/octet-stream"))
						{
							mimeType = getRequest().getSession().getServletContext().getMimeType(multipartFile.getOriginalFilename());
						}
						if (mimeType == null)
						{
							mimeType = "application/octet-stream";
						}
						attachment.setMimeType(mimeType);

						int fileType = AttachmentService.getFileType(mimeType);
						attachment.setType(fileType);

						String targetFolder = TimeUtil.getStr(new Date(), "yyyy/MM/");
						String targetName = TimeUtil.getStr(new Date(), "yyyyMMddHHmm") + "_" + StringDigest.unique_id().substring(24);
						String extension = multipartFile.getOriginalFilename().substring(multipartFile.getOriginalFilename().lastIndexOf('.'));
						String targetFullPath = 
								SimpleConfig.getConfig("file_physical_path")  
								+ SimpleConfig.getConfig("file_for_static") 
								+ targetFolder + targetName + extension;

						// Move it to the target folder
						if (CommonUtils.uploadFile(multipartFile, targetFullPath))
						{
							attachment.setPath(targetFolder + targetName + extension);
							AttachmentService.add(attachment);
							attachments.add(attachment);
						}
						else
							logger.error("IOException: can not move file to " + targetFullPath);
					}

					// attachment end
				}
				else
				{
					tags = ticket.getTags();

					if (id > 0L)
					{
						attachments = AttachmentService.getAttachmentsByPageAndCondition(
								0, 
								10, 
								AttachmentService.ORDERBY_CREATE_TIME, 
								0, 
								ticket.getId(), 
								0L,
								0L);
					}
					else
					{
						// When adding new ticket, load only the attachments created by the user self
						attachments = AttachmentService.getAttachmentsByPageAndCondition(
								0, 
								10, 
								AttachmentService.ORDERBY_CREATE_TIME, 
								0, 
								0L, 
								0L,
								getSession().getSession_uuid());
					}
				}
			}
		}

		private boolean attachmentValidate(MultipartFile multipartFile)
		{
			boolean flag = true;

			long maxSize = AttachmentService.SIZE_LIMIT;
			if (multipartFile.getSize() >= maxSize)
			{
				flag = false;
				this.put_error_msg("fileupload", langRes.get("attachment.file-size-exceed-limit"));
			}
			return flag;
		}

		@Override
		protected boolean validate() 
		{
			boolean flag = true;
			if (ticket.getProjectId() == 0)
			{
				flag = false;
				put_error_msg("project_id", langRes.get("global.content-cannot-be-empty"));
			}
			else
			{
				Project dummy = ProjectService.getProject(ticket.getProjectId());
				if (dummy == null)
				{
					flag = false;
					put_error_msg("project_id", langRes.get("project.project-not-exist"));
				}
			}

			if (ticket.getSubject().length() == 0)
			{
				flag = false;
				put_error_msg("subject", langRes.get("global.content-cannot-be-empty"));
			}

			if (ticket.getContent().length() == 0)
			{
				flag = false;
				put_error_msg("ticket_content", langRes.get("global.content-cannot-be-empty"));
			}

			if (ticket.getDueDate() != null && ticket.getStartDate() != null 
					&& ticket.getDueDate().before(ticket.getStartDate()))
			{
				flag = false;
				put_error_msg("due_date", langRes.get("ticket.due-cannot-earlier-than-start"));
			}

			return flag;
		}
	}
}
